#include "Cluster.h"
#include "Log.h"

ID_Generator Cluster::IDs;

Cluster::Cluster(const Pile *pile, int color) {
    init(pile, color);
}

void Cluster::init(const Pile *pile, int color) {
    LOG_ENTER(CLUSTER,"Cluster::init (constructor)");

    ID         = IDs.next();
    this->items = pile;

    LOG(CLUSTER) << " cluster ID "  << ID << " (" << items->n << " items)";
    items->write_IDs(Log::output);
    LOG(CLUSTER) << ".";

    extend_labels(color);

    LOG_EXIT();
}

void Cluster::write(std::ostream& os) {
    LOG_ENTER(CLUSTER,"Cluster::write");

    os << "Cluster ID " << ID << ":\n";
    items->write(os);
    os.flush();

    LOG_EXIT();
}

//
// Append a digit to each item's label.
//
void Cluster::extend_labels(int last_digit) {
    LOG_ENTER(CLUSTER,"Cluster::extend_labels");

    Iterator<Item*> *iter = items->new_iterator();
    while (iter->has_next()) {
        Item *pt = iter->get_next();
        pt->append_label_digit(last_digit + 1);
    }
    delete iter;
    LOG_EXIT();
}

// Splice another cluster onto the end of this one.
void Cluster::append(Cluster *other) {
    items->append(other->items);
}

void Cluster::read_from_ID_file(std::string& filename,
                                Pile *all_items,
                                std::vector<Cluster*>& clusters) {
    // Given a list of Items,
    // and a file with a collection of Item IDs,
    // build a bunch of clusters.

    // Since the file has only IDs, need a map of ID to Item
    std::unordered_map<int, Item*> ID_to_item;
    Iterator<Item*> *iter = all_items->new_iterator();
    while (iter->has_next()) {
        Item *item = iter->get_next();
        int ID = item->ID;
        ID_to_item[ID] = item;
    }
    delete iter;

    // Now, go through ID file and build the clusters.
    clusters.clear();

    std::ifstream file(filename.c_str());
    std::string line;
    while (!file.eof()) {
        Pile* items = new Pile_List();
        getline(file, line);
        Parser p(line);
        while (!p.done()) {
            int ID;
            p.match_int(ID);
            Item *item = ID_to_item[ID];
            items->add(item);
        }
        Cluster *cluster = new Cluster(items, Color::Type::BLACK);
        clusters.push_back(clusters);
    }
}
